#ifndef POPULATION_H
#define POPULATION_H

#include "molCluster.h"
#include <iostream.h>


//! This function sorts a vector of <double>s (see misc.cpp for implementation).
/*!
	\param a the vector to be sorted.
*/
extern void sortDoubleVector( vector<double>& a );

//! This function sorts a vector of <molCluster>s (see misc.cpp for implementation).
/*!
        \param a the vector to be sorted.
*/
extern void sortMolClusterVector( vector<molCluster>& a );


/*! \file */
//! This class provides an abstraction of a population of molClusters.

/*! This class describes a population of molClusters with different operations to support Evolutionary Algorithm such as different selection and statistical methods.  */

class population{

	//! This friend function output the info of the population <aPopulation> into an output stream <out>.
        /*!
                 \param out an output stream.
                 \param aPopulation a population which info is to be printed out.
        */
        friend ostream& operator<<( ostream& out, population& aPopulation);

public:
	vector< molCluster > pop;
	int popSize;

	/*! \brief constructor */
	population( );
	
	//! This copy constructor generates the population with another population's values.
        /*!
                \param rhs another population to be copied.
        */
	population( const population& rhs );

	//! This constructor generates the population of size <aSize>.
        /*!
                \param aSize size of new population to generate.
        */
	population( int aSize );

	//! This constructor generates the molCluster with the input values.
        /*!
                 \param popFileName name of file containing the population info.
                 \param molSettingFileName name of file containing the molCluster info.
                 \param anEvaluator pointer to evaluator function for each molCluster.
        */
	population( string& popFileName, string& molSettingFileName,  vector<double>(*anEvaluator)(vector<atom>& a, int optimize) );		
	
	/*! \brief destructor */
	~population( );
	
	//! This function selects the best molCluster.
        /*!
                 \param aMolCluster selected molCluster.
        */
	void selectOneBest( molCluster& aMolCluster );
	
	//! This function selects <n> best molClusters.
        /*!
                 \param n number of molClusters to be selected.
                 \param molClusters selected molClusters.
        */
	void selectNBest( int n, vector<molCluster>& molClusters );

	//! This function selects a random molCluster.
        /*!
                 \param aMolCluster selected molCluster.
        */
	void selectOneRandom( molCluster& aMolCluster );

	//! This function selects <n> random molClusters.
        /*!
                 \param n number of molClusters to be selected.
                 \param molClusters selected molClusters.
        */
	void selectNRandom( int n, vector<molCluster>& molClusters );

	//! This function selects the worst molCluster.
        /*!
                 \param aMolCluster selected molCluster.
        */
	void selectOneWorst( molCluster& aMolCluster );

	//! This function selects <n> worst molClusters.
        /*!
                 \param n number of molClusters to be selected.
                 \param molClusters selected molClusters.
        */
	void selectNWorst( int n, vector<molCluster>& molClusters );

	//! This function selects a molCluster based on tournament selection of size <tournamentSize>.
        /*!
                 \param tournamentSize size of tournament selection.
                 \param aMolCluster selected molCluster.
        */
	void selectOneTournament( int tournamentSize, molCluster& aMolCluster );

	//! This function selects <n> molClusters based on tournament selection of size <tournamentSize>.
        /*!
                 \param n number of molClusters to be selected.
                 \param tournamentSize size of tournament selection.
                 \param molClusters selected molClusters.
        */
	void selectNTournament( int n, int tournamentSize, vector<molCluster>& molClusters );

	//! This function selects <n> molClusters based on Stochastic Universal Sampling (SUS).
        /*!
                 \param n number of molClusters to be selected.
                 \param molClusters selected molClusters.
        */
	void selectNSUS( int n, vector<molCluster>& molClusters );

	//! This function performs population replacement, based on elitism or no elitism.
        /*!
                 \param nElitist number of elitist molClusters.
                 \param rhs population to considered to replace the invoking population.
        */
        void replaceMuLambda( int nElitist, population& rhs );
	

	//! Index([]) operator. This operator returns molCluster <index>.
        /*!
               \param index index of molCluster to be retrieved.
        */
	molCluster& operator[]( int index );

	//! Assignment(=) operator.
        /*!
                \param rhs another population to be assigned to invoking population.
        */
	population& operator=( const population& rhs );
	
	//! Addition(+) operator. This operator merges the lhs(invoking) population with the <rhs> population.
        /*!
                \param rhs another population to be merged with lhs(invoking) population.
        */
	population& operator+( const population& rhs );

	//! Addition and assignment(+=) operator. This operator merges the lhs(invoking) population with the <rhs> population.
        /*!
        	\param rhs another population to be merged with lhs(invoking) population.
        */
	population& operator+=( const population& rhs );

	//! This function sorts the population based on fitness values.
	void sort();

	//! This function returns the best(minimum) of the population's fitness values.
	double bestFitness();

	//! This function returns the worst(maximum) of the population's fitness values.
	double worstFitness();

	//! This function returns the median of the population's fitness values.
	double medianFitness();

	//! This function returns the mean of the population's fitness values.
	double meanFitness();
	
	//! This function returns the standard deviation of the population's fitness values.
	double stdevFitness();	
	
	//! This function returns the population size.
	int size();

	//! This function prints the content of this population to file output stream <out>.
        /*!
       		\param out file output stream.
        */
        void printToFileStream( ofstream& out );
};

#endif
